package com.cisco.pso;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * match file according to file name. usually compare pso with old base.
 * 
 * @author jackding
 * 
 */
public class PsoFileMatcher {
	public static enum MatchResult {

		/**
		 * restrict mode, module and sub-folder must be matched
		 */
		One,
		/**
		 * restrict mode, module and sub-folder must be matched
		 */
		Many,
		/**
		 * loose mode, if failed to match one-to-one strictly, it will not
		 * compare module and sub-folder.
		 */
		Candidates,
		/**
		 * even no candidate in loose mode.
		 */
		None
	};

	private List<FileItem> baseFiles;
	private List<FileItem> psoFiles;

	private Map<String, MatchResult> matchResults = new HashMap<String, MatchResult>();

	private Map<String, List<String>> fileMap = new HashMap<String, List<String>>();

	public void match(List<FileItem> baseFiles, List<FileItem> psoFiles) {
		this.baseFiles = baseFiles;
		this.psoFiles = psoFiles;

		Set<String> basedModulesForPsoShared = new HashSet<String>();
		basedModulesForPsoShared.add("waf");
		basedModulesForPsoShared.add("svccomponents");		

		for (FileItem fileItem : psoFiles) {
			PsoFileItem psoFileItem = (PsoFileItem) fileItem;

			// first time, find in strict mode, hope it will find unique result
			List<FileItem> matchedBaseFiles = findInBase(baseFiles,
					basedModulesForPsoShared, psoFileItem, true, true);

			MatchResult result = null;
			if (matchedBaseFiles.size() == 1)
				result = MatchResult.One;
			else
				result = matchedBaseFiles.size() == 0 ? MatchResult.None
						: MatchResult.Many;

			if (matchedBaseFiles.size() == 0) {
				// second time, in loose mode
				matchedBaseFiles = findInBase(baseFiles,
						basedModulesForPsoShared, psoFileItem, true, false);
				if (matchedBaseFiles.size() > 0)
					result = MatchResult.Candidates;
			}

			if (matchedBaseFiles.size() == 0) {
				// 3rd time, in loose mode
				matchedBaseFiles = findInBase(baseFiles,
						basedModulesForPsoShared, psoFileItem, false, false);
				if (matchedBaseFiles.size() > 0)
					result = MatchResult.Candidates;
			}

			if (matchedBaseFiles.size() > 0) {
				// StringBuilder sb = new StringBuilder();
				// for (int i = 0; i < matchedBaseFiles.size(); i++) {
				// FileItem fi = matchedBaseFiles.get(i);
				// if (i > 0)
				// sb.append(",");
				// sb.append(fi.getFullName());
				// }

				List<String> baseFileNames = new ArrayList<String>();
				for (FileItem fi : matchedBaseFiles) {
					baseFileNames.add(fi.getFullName());
				}

				fileMap.put(psoFileItem.getFullName(), baseFileNames);

			}

			matchResults.put(psoFileItem.getFullName(), result);
		}

	}

	private List<FileItem> findInBase(List<FileItem> baseFiles,
			Set<String> basedModulesForPsoShared, PsoFileItem psoFileItem,
			boolean checkModule, boolean checkSubfolder) {

		List<FileItem> matchedBaseFiles = new ArrayList<FileItem>();

		for (FileItem baseFileItem : baseFiles) {
			String baseFileName = null;
			String psoFileName = null;

			if (checkSubfolder) {
				baseFileName = baseFileItem.getSubFolder(psoFileItem
						.getSubFolderDepth()) + baseFileItem.getShortName();
				psoFileName = psoFileItem.getSubFolder()
						+ psoFileItem.getBaseName();
			} else {
				baseFileName = baseFileItem.getShortName();
				psoFileName = psoFileItem.getBaseName();
			}

			String debugFileName = "UseMenuDisplayerTag";
			if (baseFileName.contains(debugFileName)
					&& psoFileName.contains(debugFileName)) {
				// System.out.println("bingo");
			}

			boolean isModuleMatch = true;

			if (checkModule) {
				// strict compare with module, but the pso-shared module is for
				// base waf module
				String baseModule = baseFileItem.getModule();
				String psoModule = psoFileItem.getModule();

				isModuleMatch = baseModule.equals(psoModule);

				if (basedModulesForPsoShared.contains(baseModule)
						&& psoModule.equals("shared"))
					isModuleMatch = true;
			}

			if (isModuleMatch && baseFileName.equalsIgnoreCase(psoFileName))
				matchedBaseFiles.add(baseFileItem);

		}
		return matchedBaseFiles;
	}

	public List<FileItem> getBaseFiles() {
		return baseFiles;
	}

	public void setBaseFiles(List<FileItem> baseFiles) {
		this.baseFiles = baseFiles;
	}

	public List<FileItem> getPsoFiles() {
		return psoFiles;
	}

	public void setPsoFiles(List<FileItem> psoFiles) {
		this.psoFiles = psoFiles;
	}

	public Map<String, MatchResult> getMatchResults() {
		return matchResults;
	}

	public void setMatchResults(Map<String, MatchResult> matchResults) {
		this.matchResults = matchResults;
	}

	public Map<String, List<String>> getFileMap() {
		return fileMap;
	}

	public void setFileMap(Map<String, List<String>> fileMap) {
		this.fileMap = fileMap;
	}

}
